﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SyncList.UserInterface.ValueObject;
using System.Collections.ObjectModel;
using SyncList.Business.ValueObject;
using SyncList.Business.Persistence;

namespace SyncList.UserInterface
{

    /// <summary>
    /// Interaction logic for UCExplorer.xaml
    /// </summary>
    public partial class UCExplorer : UserControl
    {

        #region Attributs

      
        /// <summary>
        /// Données
        /// </summary>
        private ExplorerData _data = new ExplorerData();

        #endregion

        #region Constructeur

        public UCExplorer()
        {
            InitializeComponent();

            this.DataContext = Data;
            //this.ListBoxExplorer.ItemsSource = Data.FilteredItems;

            //this.ListBoxExplorer.SelectionChanged += new SelectionChangedEventHandler(ListBoxExplorer_SelectionChanged);
            this.ListBoxExplorer.MouseDoubleClick += new MouseButtonEventHandler(ListBoxExplorer_MouseDoubleClick);
        

            ucNavigationPath.DirectorySelected += new EventHandler<DirectoryEventArgs>(ucNavigationPath_DirectorySelected);

            PrepareListBoxForDrag(this.ListBoxExplorer);
            PrepareListBoxForDrop(this.ListBoxExplorer);
        }

        /// <summary>
        /// Préparer la liste pour le Drag (source)
        /// </summary>
        /// <see cref="http://blogs.msdn.com/b/marcelolr/archive/2007/06/09/basics-of-data-bound-drag-drop-in-wpf.aspx"/>
        /// <param name="listbox"></param>
        private void PrepareListBoxForDrag(ListBox listbox)
        {
            listbox.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(listbox_PreviewMouseLeftButtonDown);
            listbox.PreviewMouseMove += new MouseEventHandler(listbox_PreviewMouseMove);
            listbox.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(listbox_PreviewMouseLeftButtonUp);
            //listbox.Drop += new DragEventHandler(ListboxDrop);
        }

      

        /// <summary>
        /// Préparer la liste pour le Drop (cible)
        /// </summary>
        /// <param name="listbox"></param>
        private void PrepareListBoxForDrop(ListBox listbox)
        {
            listbox.AllowDrop = true;
            //listbox.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(ListboxPreviewMouseLeftButtonDown);
            //listbox.PreviewMouseMove += new MouseEventHandler(ListboxPreviewMouseMove);
            //listbox.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(ListboxPreviewMouseLeftButtonUp);
            listbox.Drop += new DragEventHandler(ListboxDrop);
        }



        #endregion

        #region Accesseurs

        
        /// <summary>
        /// Données
        /// </summary>
        public ExplorerData Data
        {
            get { return(_data); }
        }


        #endregion

        #region Evénements

        /// <summary>
        /// Eléments posés sur la liste
        /// </summary>
        public event EventHandler<DragDropEventArgs> ItemsDropped;

        protected void OnItemsDropped(ItemBase[] items)
        {
            if (ItemsDropped != null)
                ItemsDropped(this, new DragDropEventArgs(items));
        }



        /// <summary>
        /// Eléments posés sur la liste
        /// </summary>
        public event EventHandler<DragDropEventArgs> ItemsSelected;

        protected void OnItemsSelected(ItemBase[] items)
        {
            if (ItemsSelected != null)
                ItemsSelected(this, new DragDropEventArgs(items));
        }

        

        #endregion

        #region Propriétés de dépendance


        private static DependencyProperty DraggingElementProperty = DependencyProperty.RegisterAttached("DraggingElement", typeof(ItemBase), typeof(UCExplorer), new FrameworkPropertyMetadata(null));
        private static DependencyProperty IsDownProperty = DependencyProperty.RegisterAttached("IsDown", typeof(bool), typeof(UCExplorer), new FrameworkPropertyMetadata(false));
        private static DependencyProperty StartPointProperty = DependencyProperty.RegisterAttached("StartPoint", typeof(Point), typeof(UCExplorer), new FrameworkPropertyMetadata(default(Point)));

        #endregion

        #region Gestion d'événements



        /// <summary>
        /// Lâcher un item sur la ListBox cible
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ListboxDrop(object sender, DragEventArgs e)
        {
            ListBox listbox = (ListBox)sender;
            ObservableCollection<ItemBase> collection = (ObservableCollection<ItemBase>)listbox.ItemsSource;
            if (e.Data.GetDataPresent(DataFormats.UnicodeText, true))
            {
                ItemBase element = (ItemBase)e.Data.GetData(DataFormats.UnicodeText, true);
                OnItemsDropped(new ItemBase[] { element });

                //collection.Add((ItemBase)e.Data.GetData(DataFormats.UnicodeText, true));
                e.Effects = ((e.KeyStates & DragDropKeyStates.ControlKey) != 0) ? DragDropEffects.Copy : DragDropEffects.Move;
                e.Handled = true;
            }
        }



        /// <summary>
        /// Relâcher le bouton gauche
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void listbox_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ListBox listbox = (ListBox)sender;
            listbox.ClearValue(IsDownProperty);
            listbox.ClearValue(DraggingElementProperty);
            listbox.ClearValue(StartPointProperty);
        }

        /// <summary>
        /// Déplacer (si pendant appuyé c'est un Drag)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void listbox_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            ListBox listbox = (ListBox)sender;

            bool isDown = (bool)listbox.GetValue(IsDownProperty);
            if (!isDown)
            {
                return;
            }

            Point startPoint = (Point)listbox.GetValue(StartPointProperty);

            if (Math.Abs(e.GetPosition(listbox).X - startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
                Math.Abs(e.GetPosition(listbox).Y - startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
            {
                DragStarted(listbox);
            }
        }

        /// <summary>
        /// Appuyer sur le bouton gauche
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void listbox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ListBox listbox = (ListBox)sender;
            ItemBase s = GetBoundItemFromPoint(listbox, e.GetPosition(listbox));
            if (s != null)
            {
                listbox.SetValue(IsDownProperty, true);
                listbox.SetValue(DraggingElementProperty, s);
                listbox.SetValue(StartPointProperty, e.GetPosition(listbox));
            }
        }



        /// <summary>
        /// Sélection du double clic
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ListBoxExplorer_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            ItemBase item = ListBoxExplorer.SelectedItem as ItemBase;
            if (item != null)
            {
                DirectoryContent itemDirectory = item as DirectoryContent;
                if (itemDirectory != null)
                {
                    Data.CurrentDirectory = itemDirectory;
                }

                // - Déclencher la sélection
                FileItem file = item as FileItem;
                if (file != null)
                    OnItemsSelected(new ItemBase[] { file });
            }
        }




        private void DragStarted(ListBox listbox)
        {
            listbox.ClearValue(IsDownProperty); // SetValue to false would also work.

            // Add the bound item, available as DraggingElement, to a DataObject, however we see fit.
            ItemBase draggingElement = (ItemBase)listbox.GetValue(DraggingElementProperty);
            DataObject d = new DataObject(DataFormats.UnicodeText, draggingElement);
            DragDropEffects effects = DragDrop.DoDragDrop(listbox, d, DragDropEffects.Copy | DragDropEffects.Move);
            if ((effects & DragDropEffects.Move) != 0)
            {
                // Move rather than copy, so we should remove from bound list.
                ObservableCollection<ItemBase> collection = (ObservableCollection<ItemBase>)listbox.ItemsSource;
                //collection.Remove(draggingElement);
            }
        }


        /// <summary>
        /// Sélection de répertoire
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ucNavigationPath_DirectorySelected(object sender, DirectoryEventArgs e)
        {
            Data.CurrentDirectory = e.Directory;
        }


        #endregion

        #region Méthodes privées


        /// <summary>
        /// Renvoyer l'item sous la sélection
        /// </summary>
        /// <param name="box"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        private ItemBase GetBoundItemFromPoint(ListBox box, Point point)
        {
            UIElement element = box.InputHitTest(point) as UIElement;
            while (element != null)
            {
                if (element == box)
                {
                    return null;
                }
                object item = box.ItemContainerGenerator.ItemFromContainer(element);
                bool itemFound = !object.ReferenceEquals(item, DependencyProperty.UnsetValue);
                if (itemFound)
                {
                    return (ItemBase)item;
                }
                else
                {
                    element = VisualTreeHelper.GetParent(element) as UIElement;
                }
            }
            return null;
        }

        #endregion
    
        /// <summary>
        /// Ajouter un item
        /// </summary>
        /// <param name="myDataList">MES listes</param>
        /// <param name="root">Racine d'exploration de la liste des autres</param>
        public void Initialize(DirectoryContent root) 
        {
            Data.Root = root;
        }


        /// <summary>
        /// Racine
        /// </summary>
        public DirectoryContent Root
        {
            get { return (Data.Root); }
            set {  Data.Root = value; }
        }

        
        /// <summary>
        /// Chemin courant
        /// </summary>
        public DirectoryContent CurrentDirectory
        {
            get { return (Data.CurrentDirectory); }
            set { Data.CurrentDirectory = value; }
        }
            




    }
}
